package simulate
{
	import away3d.core.math.MathConsts;
	
	import base.TrackPoint;
	
	import com.sections.vo.SectionBaseVO;
	import com.sections.vo.SectionLineVO;
	import com.sections.vo.SectionRoundVO;
	import com.sections.vo.SectionSlipVO;
	
	import configs.GlobalConsts;
	import configs.MakerConfig;
	
	import core.utils.FormulaUtil;
	import core.utils.MathUtil;
	
	import events.PropertyEvent;
	
	import flash.filesystem.File;
	import flash.geom.Vector3D;
	
	import managers.EventManager;
	
	import simulate.vo.CarVO;
	import simulate.vo.TempCountVo;
	
	import views.AlertPanel;

	public class SimulateSystem
	{
		private static var points:Vector.<TrackPoint>
		private static var injectAngle:Number;
		private static var outAngle:Number;
		// TODO 多车模拟,可变因素模拟
		public function SimulateSystem()
		{
		}
		/**
		 * 初始化模拟系统的数值配置 
		 * @param value		关键点信息
		 * @param injection	开始角度
		 * @param outjectAngle 结束角度
		 * 
		 */		
		public static function init(value:Vector.<TrackPoint>,injection:Number = 0, outjectAngle:Number=0):void
		{
			//todo 关键点需要排序
			points = value;
			injectAngle = injection;
			outAngle = outjectAngle;
		}
		/**
		 * 开始模拟 
		 * @param cars
		 * 
		 */		
		public static function simulate(cars:Vector.<CarVO>,grav:Number=9.8):void
		{
			var tempCountVos:Vector.<TempCountVo> = new Vector.<TempCountVo>(cars.length);
			var index:int = 0;
			
			while(index < tempCountVos.length)
			{
				tempCountVos[i] = new TempCountVo();
				index++;
			}
			/**当前段的最大速度 */
			var currentMaxSpeed:Number;
			/** 这个应该出现在路径配置表里面 */
			var totalDist:Number=0;
			/** 记录总长度 */
			var sectionArr:Array = [];
			
			/**这个是所有车公用的，不用单独出来*/
			var gravity:Number = grav;
			var xml:XML =XML("<root />");
			var info:XML=XML("<info />");
			info.@name = "akiyama";
			info.@gravity = grav;
			
			
			var carConfig:XML = cars[0].carConfig();
			/** 圆形方程 */
			var circle:Object;
			/** 圆心 */
			var center:Vector3D;
			/** 下一个参考点  */
			var nextRefer:TrackPoint;
			/** 不用抽出，关键点的长度 */
			var len:int = points.length-1;
			/** 两点之间的距离 */
			var distance:Number = 0;
			
			/** 当前速度 */	
			var currentSpeed:Number = 0;
			/** 以前所有时间 */	
			var currentTime:Number = 0;
			/** 当前角度 */	
			var currentAngle:Number = 0;
			/** 实际上参考时间 */	
			var referTime:Number = 0;
			/** 理论上使用时间*/	
			var costTime:Number = 0;
			/** 后备时间*/	
			var bearTime:Number = 0;
			/** 当前加速度*/	
			var curAccelerate:Number;
			/**  偏移角度*/	
			var offset_angle:Number = 0;
			/** 总量:(t+v/a)^2 = v^2 + 2*s*a/a^2; t+v/a的根*/	
			var totalMount:Number = 0;
			var id:int = -1;
			var vec0:Vector3D = new Vector3D();
			var vec1:Vector3D = new Vector3D();
			var vec2:Vector3D = new Vector3D();
			var yAngle:Number;
			var sectionVo:SectionBaseVO;
			for(var i:int = 0; i < len; i++)
			{
				if(i == 0 )
				{
					currentAngle = injectAngle;
				}
				id++;
				var type:String = points[i].type;
				
				sectionVo =  createSectionVO(type,points[i+1].type);
				
				sectionVo.id = id;
				sectionVo.v = currentSpeed*0.001;// milseconds
				sectionVo.startPos =  new Vector3D(points[i].position.x,points[i].position.y,points[i].position.z);
				/** count yAngle*/	
				vec0 = points[i+1].position.subtract(points[i].position);
				vec0.z = 0;
				vec0.normalize();
				if(vec0.y)
				{
					yAngle = Vector3D.angleBetween(vec0, new Vector3D(1,0,0));
					if(points[i].position.y > points[i+1].position.y)
					{
						yAngle = -yAngle;
					}
				}else
				{
					yAngle = 0;
				}
				/** save as radian*/	
				sectionVo.yRad = yAngle;
				/** line section*/	
				if(type == MakerConfig.NORMALPOINT)
				{
					/** add:type*/	
					SectionLineVO(sectionVo).sAng = currentAngle;
					
					/** count:accerate*/	
					curAccelerate = cars[0].accelate - Math.sin(yAngle) * grav;
					/** 当前段的最大速度*/	
					currentMaxSpeed = cars[0].maxSpeed*Math.cos(yAngle);
					sectionVo.minV = cars[0].minSpeed*Math.cos(yAngle);
					/** count:direction according to next point*/	
					vec0.copyFrom(points[i].position);
					vec1.copyFrom(points[i+1].position);
					vec2 = vec1.subtract(vec0);
					vec2.normalize();
					
					SectionLineVO(sectionVo).direction.copyFrom(vec2);
					
					distance = Vector3D.distance(points[i].position,points[i+1].position);
					totalMount = Math.sqrt((currentSpeed*currentSpeed+2*distance*curAccelerate)/(curAccelerate*curAccelerate));
					if(curAccelerate < 0)
					{
						if(distance < -0.5 * cars[0].accelate)
						{
							trace("速度不够 keypoint id="+points[i].id);
						}else
						{
							costTime = Math.abs(- currentSpeed/curAccelerate - totalMount);
						}
					}else
					{
						costTime = Math.abs(-currentSpeed/curAccelerate + totalMount);
					}
					/** time to accelerate to maxspeed*/	
					referTime = (currentMaxSpeed - currentSpeed)/curAccelerate;
					
					/** 计算 offset_angle*/	
					if(i > 1 && points[i-1].type == MakerConfig.RNDSLDINNER)
					{
						offset_angle = 0;
					}else
					{
						var temp_0:Number = MathUtil.angleBetweenPoint(new Vector3D
							(
								Math.cos(currentAngle*MathConsts.DEGREES_TO_RADIANS),
								0,
								Math.sin(currentAngle*MathConsts.DEGREES_TO_RADIANS)),
							SectionLineVO(sectionVo).direction)
							*MathConsts.RADIANS_TO_DEGREES;
						offset_angle = temp_0;
					}
					
					if(referTime <= 0)// 1 part:average speed	
					{
						SectionLineVO(sectionVo).v = currentSpeed * GlobalConsts.MILLIUNIT;
						SectionLineVO(sectionVo).oAng = offset_angle; 
						SectionLineVO(sectionVo).a = 0;
						SectionLineVO(sectionVo).id = id;
						SectionLineVO(sectionVo).d = distance;
						costTime = distance/currentSpeed;
						SectionLineVO(sectionVo).t = (currentTime+costTime)*1000;
					}else if(costTime > referTime)// 2 parts
					{
						var tempDistance:Number = currentSpeed*referTime + (curAccelerate*referTime*referTime>>1);
						bearTime = ( distance -  tempDistance)/currentMaxSpeed;
						SectionLineVO(sectionVo).a = curAccelerate*GlobalConsts.POWMILIUNIT;// milseconds
						SectionLineVO(sectionVo).d = tempDistance;
						SectionLineVO(sectionVo).t = int((currentTime + referTime)*1000);
						SectionLineVO(sectionVo).oAng = offset_angle*referTime/(referTime + bearTime);
						SectionLineVO(sectionVo).minV = 0;
						
						carConfig.appendChild(sectionVo.toXML());
						currentSpeed = currentMaxSpeed;
						
						/** next part*/	
						id++;
						sectionVo = new SectionLineVO();
						SectionLineVO(sectionVo).direction.copyFrom(vec2);
						vec2.scaleBy(tempDistance);
						
						sectionVo.startPos = new Vector3D(points[i].position.x + vec2.x,points[i].position.y + vec2.y,points[i].position.z + vec2.z);
						sectionVo.id = id;
						sectionVo.v = currentSpeed*GlobalConsts.MILLIUNIT;
						SectionLineVO(sectionVo).oAng = offset_angle*bearTime/(referTime + bearTime);
						sectionVo.a = 0;
						sectionVo.d = distance - tempDistance;
						sectionVo.yRad = yAngle;
						SectionLineVO(sectionVo).sAng = currentAngle + offset_angle*referTime/(referTime + bearTime);
						costTime = referTime + bearTime;
					}else// 1 part:change speed
					{
						sectionVo.v = currentSpeed*GlobalConsts.MILLIUNIT;
						SectionLineVO(sectionVo).oAng = offset_angle;
						sectionVo.a = curAccelerate*GlobalConsts.POWMILIUNIT;
						sectionVo.id = id;
						sectionVo.d = distance;
						currentSpeed = currentSpeed + curAccelerate * costTime;
					}
					currentAngle += offset_angle;
				}else 
				{
					curAccelerate = -cars[0].brake;
					if(type == MakerConfig.NMLRNSTART)
					{
						nextRefer = points[i+1].type == MakerConfig.RNDSLDINNER ? points[i+1] : points[i+2];
						circle = FormulaUtil.getRingFormula(points[i].position,points[i+1].position,points[i+2].position);
						center = new Vector3D(circle.a,circle.b,circle.c);
					}else
					{
						nextRefer = points[i+1];
					}
						
					//计算圆公式
					SectionRoundVO(sectionVo).centerPoint = new Vector3D(circle.a,circle.b,circle.c);
					SectionRoundVO(sectionVo).r = circle.r;
					SectionRoundVO(sectionVo).a = curAccelerate*GlobalConsts.POWMILIUNIT;
					sectionVo.yRad = 0;
					// 计算offset_angle
					vec0 = points[i].position.subtract(center);
					vec1 =  nextRefer.position.subtract(center);
					var offset:Number = Vector3D.angleBetween(vec0,vec1);
					SectionRoundVO(sectionVo).spinAng = offset * MathConsts.RADIANS_TO_DEGREES;
					//计算当前角度
					vec0.normalize();
					var factor:int = vec0.z > 0 ? 1 : -1;
					currentAngle = factor * Vector3D.angleBetween(new Vector3D(1,0,0),vec0)*MathConsts.RADIANS_TO_DEGREES;
					SectionRoundVO(sectionVo).rAng = currentAngle;
					//计算总体距离
					distance = Math.abs(circle.r * offset);
					sectionVo.d = distance;
					//准备参考值，计算花费时间
					totalMount = Math.sqrt((currentSpeed*currentSpeed+2*distance*curAccelerate)/(curAccelerate*curAccelerate));
					costTime = Math.abs(- currentSpeed/curAccelerate - totalMount);
					//加速到极限速度的时间
					referTime = (cars[0].minRndSpeed - currentSpeed)/curAccelerate;
					//计算漂移角度
					if(points[i].type == MakerConfig.RNDSLDINNER)
					{
						vec0.copyFrom(points[i+1].position);
						vec1.copyFrom(points[i+2].position);
						var temp:Vector3D = vec1.subtract(vec0);
						temp.normalize();
						var tempAngle:Number = MathUtil.angleFromX(temp)*MathConsts.RADIANS_TO_DEGREES;
						SectionSlipVO(sectionVo).slipAngle = tempAngle - currentAngle - 90;
					}
					
					if(costTime > referTime)//如果是分两段
					{
						tempDistance = currentSpeed*referTime + (curAccelerate*referTime*referTime>>1);
						sectionVo.v = currentSpeed*GlobalConsts.MILLIUNIT;
						sectionVo.minV = cars[0].minRndSpeed*GlobalConsts.MILLIUNIT;
						sectionVo.t = int((currentTime + referTime)*1000);
						sectionVo.d = tempDistance;
						SectionRoundVO(sectionVo).spinAng = MathConsts.RADIANS_TO_DEGREES * offset * tempDistance/distance;
						carConfig.appendChild(sectionVo.toXML());
						id++;
						
						////////////////不华丽也是分割线//////////////////////////////
						bearTime = (distance - tempDistance)/cars[0].minRndSpeed;
						costTime = referTime + bearTime;
						if(points[i].type == MakerConfig.RNDSLDINNER)
						{
							sectionVo = new SectionSlipVO();
						}else
						{
							sectionVo = new SectionRoundVO();
						}
						
						sectionVo.id = id;
						sectionVo.v = cars[0].minRndSpeed*GlobalConsts.MILLIUNIT;
						sectionVo.a = 0;
						SectionRoundVO(sectionVo).centerPoint = center;
						currentAngle = currentAngle + MathConsts.RADIANS_TO_DEGREES*offset * tempDistance/distance;
						
						sectionVo.startPos = new Vector3D(
							center.x+circle.r*Math.cos(currentAngle*MathConsts.DEGREES_TO_RADIANS + offset * tempDistance/distance),
							center.y,
							center.z+circle.r*Math.sin(currentAngle*MathConsts.DEGREES_TO_RADIANS + offset * tempDistance/distance));
						tempDistance = distance - tempDistance;
						
						sectionVo.d = tempDistance;
						sectionVo.yRad = 0;
						SectionRoundVO(sectionVo).r = circle.r;
						SectionRoundVO(sectionVo).spinAng = offset * MathConsts.RADIANS_TO_DEGREES * tempDistance/distance;
						SectionRoundVO(sectionVo).rAng = currentAngle ;
						
						currentSpeed =  cars[0].minRndSpeed;
						
					}else if(costTime <= referTime)//纯加速
					{
						sectionVo.v = currentSpeed*GlobalConsts.MILLIUNIT;
						currentSpeed = currentSpeed + curAccelerate*costTime;
					}else if(isNaN(totalMount))//不知道
					{
						sectionVo.a = 0;
						currentSpeed = cars[0].minRndSpeed;
						sectionVo.v = currentSpeed*GlobalConsts.MILLIUNIT;
						costTime = distance/currentSpeed;
					}
					EventManager.getInstance().dispatchEvent(new PropertyEvent(PropertyEvent.DRAW_CENTRE,center));
					if(sectionVo is SectionSlipVO)
					{
						currentAngle = SectionSlipVO(sectionVo).slipAngle + currentAngle + 90;
					}else
					{
						currentAngle = SectionRoundVO(sectionVo).spinAng + currentAngle + 90;
					}
					
					if(points[i+1].type != MakerConfig.RNDSLDINNER && points[i].type == MakerConfig.NMLRNSTART)
					{
						i++;
					}
				}
				sectionVo.minV = cars[0].minRndSpeed*GlobalConsts.MILLIUNIT;
				currentTime += costTime;
				sectionVo.t = int(currentTime*1000);
				
				carConfig.appendChild(sectionVo.toXML());
			}
			totalDist += distance;
			
			// TODO 需要根据花费时间进行判断
			info.@win = cars[0].id;
			xml.appendChild(info);
			
			xml.appendChild(carConfig);
			info.@t = currentTime*1000;// milseconds
			info.@d = totalDist;
			save(xml);
		}
		
		private static function save(xml:XML):void
		{
			var file:File = File.applicationDirectory;
			file.save(xml,"simulation.xml");
		}
		/**
		 * 根据当前关键点类型和下一个关键点类型创建线段vo
		 * @param type
		 * @param nextType
		 * @return 
		 * 
		 */		
		private static function createSectionVO(type:String,nextType:String):SectionBaseVO
		{
			var vo:SectionBaseVO;
			switch(type)
			{
				case MakerConfig.NORMALPOINT:
					vo = new SectionLineVO;
					break;
				case MakerConfig.NMLRNSTART:
					vo = new SectionRoundVO();
					break;
				case MakerConfig.RNDSLDINNER:
					vo = new SectionSlipVO();
					break;
				default:
					AlertPanel.getInstance().alert("Type Error: " + type + " , " + nextType);
					break;
			}
			return vo;
		}
	}
}